import sys, os, json
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QAction, QFileDialog, QVBoxLayout, QHBoxLayout, \
    QWidget, QLabel, QSlider, QPushButton, QListWidget
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QTextCursor
import pyttsx3


# 获取依赖库   pip freeze > requirements.txt
# 打包  pyinstaller -F -w .\main.py


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.txt_file_name = None
        self.text_edit = QTextEdit(self)
        self.text_edit.setStyleSheet("font-size: 16pt;")
        # self.text_edit.setEnabled(False)
        self.setCentralWidget(self.text_edit)

        open_action = QAction('Open', self)
        open_action.triggered.connect(self.open_file)

        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(open_action)

        self.play_button = QPushButton("Play", self)
        self.play_button.clicked.connect(self.speak_text)
        self.play_button.setEnabled(False)

        # 添加一个滑块用于调整播放速度
        self.speed_label = QLabel("Speed: 2x", self)
        self.speed_slider = QSlider(self)
        self.speed_slider.setOrientation(Qt.Horizontal)
        self.speed_slider.setMinimum(50)  # 最慢速度
        self.speed_slider.setMaximum(500)  # 最快速度
        self.speed_slider.setValue(400)  # 默认速度
        self.rate = 400
        self.speed_slider.valueChanged.connect(self.update_speed)

        layout = QVBoxLayout()

        self.listWidget = QListWidget(self)
        self.listWidget.itemClicked.connect(self.jump_to_section)  # 绑定点击事件
        top_layout = QHBoxLayout()
        top_layout.addWidget(self.listWidget, 2)
        top_layout.addWidget(self.text_edit, 8)
        self.section_positions = {}  # 存储章节标题及其在文本中的位置

        bottom_layout = QHBoxLayout()
        bottom_layout.addWidget(self.play_button)
        bottom_layout.addWidget(self.speed_label)
        bottom_layout.addWidget(self.speed_slider)

        layout.addLayout(top_layout)
        layout.addLayout(bottom_layout)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.setWindowTitle('Text File Reader')
        self.setGeometry(300, 100, 600, 400)

        self.engine = pyttsx3.init()
        self.lines = []
        self.current_line_index = 0
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.speak_next_line)
        self.engine.setProperty('rate', self.rate)

    def update_speed(self, value):
        """更新TTS引擎的语速"""
        self.rate = value
        self.speed_label.setText(f"Speed: {value / 200:.1f}x")  # 显示相对于默认速度的比例
        # 如果正在播放，则需要暂停当前播放，并从当前行重新开始以应用新的语速
        # if self.timer.isActive():
        #     self.pause_and_resume_speaking()

    def pause_and_resume_speaking(self):
        current_line = self.current_line_index
        self.timer.stop()
        self.engine.endLoop()  # 停止当前的语音播放
        self.current_line_index = current_line
        self.speak_text()  # 重新开始朗读，使用新的语速

    def open_file(self):
        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getOpenFileName(self, "Open Text File", "", "Text Files (*.txt);;All Files (*)",
                                                   options=options)
        if file_name:
            with open(file_name, 'r', encoding='utf-8') as file:
                data = file.read()
                self.text_edit.setText(data)
                self.lines = data.split('\n')
                print('num lines:', len(self.lines))
                self.txt_file_name = os.path.basename(file_name)
                position = 0
                for line in self.lines:
                    if line.startswith('第'):
                        self.listWidget.addItem(line)
                        self.section_positions[line] = position
                    position += len(line) + 1  # 加上换行符的长度
                self.read_data_from_json()
            self.play_button.setEnabled(True)

    def jump_to_section(self, item):
        title = item.text()
        print(title)
        if title in self.section_positions:
            cursor = self.text_edit.textCursor()
            cursor.setPosition(self.section_positions[title], QTextCursor.MoveAnchor)
            self.text_edit.setTextCursor(cursor)
            self.text_edit.ensureCursorVisible()  # 滚动到光标位置

    def highlight_line(self, line_index):
        cursor = self.text_edit.textCursor()
        start = sum(len(line) + 1 for i, line in enumerate(self.lines[:line_index]))
        end = start + len(self.lines[line_index])
        cursor.setPosition(start)
        cursor.movePosition(cursor.Right, cursor.KeepAnchor, end - start)
        self.text_edit.setTextCursor(cursor)
        self.text_edit.ensureCursorVisible()

    def speak_text(self):
        if self.engine is not None:
            self.engine.stop()
        self.engine = None

        if self.timer.isActive():
            self.timer.stop()
            self.play_button.setText("Start")
            return
        else:
            self.engine = pyttsx3.init()
            self.play_button.setText("Stop")
            self.current_line_index = self.text_edit.textCursor().blockNumber()
            self.timer.start(100)  # 每100毫秒触发一次speak_next_line

    def speak_next_line(self):
        if self.current_line_index < len(self.lines):
            line = self.lines[self.current_line_index]
            self.highlight_line(self.current_line_index)

            self.engine.setProperty('rate', self.rate)
            self.engine.say(line)
            self.engine.runAndWait()  # 注意：这个调用是阻塞的
            self.current_line_index += 1
        else:
            self.timer.stop()

    def closeEvent(self, event):
        self.save_data_to_json()
        if self.timer.isActive():
            self.timer.stop()
        if self.engine is not None:
            self.engine.stop()
        event.accept()

    def read_data_from_json(self):
        if os.path.exists('data_save.json'):
            with open('data_save.json', 'r', encoding='utf-8') as file:
                json_data = json.load(file)
                data_array = json_data['data_array']
                for data in data_array:
                    if data['file_name'] == self.txt_file_name:
                        self.current_line_index = data['read_index']
                        print('read_index:', self.current_line_index)
                        break

    def save_data_to_json(self):
        if self.txt_file_name is None:
            return
        json_path = 'data_save.json'
        is_exists = os.path.exists(json_path)
        json_data = {
            'data_array': [
                {
                    'file_name': self.txt_file_name,
                    'read_index': self.current_line_index
                }
            ]
        }
        if is_exists:
            with open(json_path, 'r', encoding='utf-8') as file:
                json_data = json.load(file)
                data_array = json_data['data_array']
                file_name_exists = False
                for data in data_array:
                    if data['file_name'] == self.txt_file_name:
                        data['read_index'] = self.current_line_index
                        file_name_exists = True
                        break
                if not file_name_exists:
                    data_array.append({
                        'file_name': self.txt_file_name,
                        'read_index': self.current_line_index
                    })

        with open(json_path, 'w', encoding='utf-8') as file:
            json.dump(json_data, file, ensure_ascii=False, indent=4)
        print("JSON文件已保存")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_win = MainWindow()
    main_win.show()
    sys.exit(app.exec_())
